﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;

namespace HttpFileServer
{
    public class RangeFileResponse : FemtoHttpd.FemtoHttpResponse
    {
        private readonly FileInfo fi;
        private readonly long _start;
        private readonly long _end;

        private RangeFileResponse(Stream output, FileInfo fi, long start, long end) : base(output)
        {
            ContentType = MiMeType.GetMiMeType(fi.Extension);
            Header["Content-Length"] = $"{end - start + 1}";
            Header["Accept-Ranges"] = "bytes";
            Header["Content-Range"] = $"bytes {start}-{end}/{fi.Length}";

            //if (Util.IsVideo(fi.Name))
           // Header["Content-Disposition"] = "inline";

            Status = new FemtoHttpd.FemtoHttpStatus(206, "Partial Content");
            this.fi = fi;
            this._start = start;
            this._end = end;
            SocketException s;
        }
        public static RangeFileResponse Create(Stream output, string fileName, string rangeHead)
        {
            var fi = new FileInfo(fileName);
            if (!fi.Exists) return null;
            var range = rangeHead.Substring(rangeHead.IndexOf("=") + 1).Split(',')[0];
            var ss = range.Split('-');
            long start = TryParse(ss[0], -1);
            long end = TryParse(ss[1], -1);
            if (start == -1 && end == -1) return null;
            if (start == -1)//最后范围
            {
                start = fi.Length - end;
                end = fi.Length - 1;
            }
            else if (end == -1)//从start开始部分范围
            {
                // start = start;
                end = fi.Length - 1;
            }
            return start >= 0 && start <= end && end < fi.Length ? new RangeFileResponse(output, fi, start, end) : null;
        }
        private static long TryParse(string v, long @default)
        {
            return long.TryParse(v, out var r) ? r : @default;
        }
        protected override void WriteContent()
        {
            using (var fs = fi.OpenRead())
            {
                if (_start > 0)
                {
                    fs.Seek(_start, SeekOrigin.Begin);
                }
                byte[] buff = new byte[1024 * 100];
                int len;
                long need = _end - _start + 1;
                while (need > 0 && (len = fs.Read(buff, 0, need > buff.Length ? buff.Length : (int)need)) > 0)
                {
                    Output.Write(buff, 0, len);
                    need -= len;
                }
            }
        }
    }
}
